using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

public class DDActionBuilder
{
    public DDNode Node { get; private set; }

    public DDActionBuilder(DDNode node)
    {
        Node = node;
    }

    public DDIntervalAction MoveTo(float duration, float x, float y)
    {
        return new DDMoveTo(duration, x, y);
    }

    public DDIntervalAction MoveTo(float duration, DDVector xy)
    {
        return new DDMoveTo(duration, xy);
    }

    public DDIntervalAction WavedMoveTo(float duration, float count, float size, DDVector xy)
    {
        return new DDIntervalAction<DDVector>(duration, xy, it => it.Position, (it, val) => { it.Position = val; },
            (v1, v2, t) =>
            {
                var ox = v2 - v1;
                var oy = new DDVector(-ox.Y, ox.X);
                oy = oy / oy.Length * size;
                return v1 + ox * t + oy * DDMath.Sin(DDMath.Lerp(0, 2 * DDMath.PI * count, t));
            });
    }

    internal DDIntervalAction RotateTo(float duration, float to)
    {
        return new DDRotateTo(duration, to);
    }

    public DDIntervalAction ScaleTo(float duration, float x, float y)
    {
        return new DDScaleTo(duration, x, y);
    }
    public DDIntervalAction ScaleTo(float duration, float xy)
    {
        return new DDScaleTo(duration, xy, xy);
    }
    public DDIntervalAction ScaleTo(float duration, DDVector xy)
    {
        return new DDScaleTo(duration, xy);
    }

    public DDIntervalAction ScaleToSizeInner(float duration, float x, float y)
    {
        return new DDScaleTo(duration, DDMath.MinXOrY(new DDVector(x, y) / this.Node.Size));
    }

    internal DDIntervalAction Delay(float duration)
    {
        return new DDDelayTime(duration);
    }

    public DDIntervalAction Exec(System.Action act)
    {
        Action safeAction = () =>
        {
            try
            {
                act();
            }
            catch (Exception ex)
            {
                DDDebug.Log(ex);
            }
            ;
        };
        return new DDInstantAction(act == null ? null : safeAction);
    }

    internal DDIntervalAction Sound(string name, bool wait)
    {
        return new DDPlayEffect(name, wait);
    }

    internal DDIntervalAction Kill()
    {
        return Exec(() => { Node.RemoveFromParent(); });
    }

    internal DDIntervalAction FlashClip()
    {
        return new DDPlayClip((DDFlashClip)Node);
    }

    internal DDAction Repeat(DDAction action)
    {
        return new DDRepeatForever(action);
    }

    internal DDIntervalAction Repeat(int count, DDIntervalAction action)
    {
        return new DDRepeat(action, count);
    }

    internal DDIntervalAction ColorTo(float duration, DDColor color, float alpha)
    {
        return ColorTo(duration, new DDColor(color, alpha));
    }
    internal DDIntervalAction ColorTo(float duration, float r, float g, float b, float alpha)
    {
        return ColorTo(duration, new DDColor(r, g, b, alpha));
    }
    internal DDIntervalAction ColorTo(float duration, DDColor color)
    {
        return new DDIntervalAction<DDColor>(duration, color, it => it.Color, (it, val) => it.Color = val, DDColor.Lerp);
    }

	internal DDIntervalAction ColorBlackTo(float duration, DDColor color)
	{
		return new DDIntervalAction<DDColor>(duration, color, it => it.ColorBlack, (it, val) => it.ColorBlack = val, DDColor.Lerp);
	}
    // -----------------------------------

    internal DDIntervalAction Ease(DDIntervalAction action, Func<float, float> func)
    {
        return new DDEase(action, func);
    }

    internal DDIntervalAction EaseIn(DDIntervalAction action)
    {
        return new DDEaseIn(action, 2.0f);
    }

    internal DDIntervalAction EaseOut(DDIntervalAction action)
    {
        return new DDEaseOut(action, 2.0f);
    }

    internal DDIntervalAction EaseElasticIn(DDIntervalAction action)
    {
        return new DDEaseElasticIn(action, 0.4f);
    }
    internal DDIntervalAction EaseElasticOut(DDIntervalAction action, float period = 0.4f)
    {
        return new DDEaseElasticOut(action, period);
    }

    internal DDIntervalAction Show()
    {
        return new DDInstantAction(() => { Node.Visible = true; });
    }

    internal DDIntervalAction Hide()
    {
        return new DDInstantAction(() => { Node.Visible = false; });
    }

    public DDAction Update(Action<float> onUpdate, float delay = 0)
    {
        return new DDUpdate(onUpdate, delay);
    }

    public DDAction Update(Action onUpdate, float delay = 0)
    {
        return new DDUpdate(dt => onUpdate(), delay);
    }
}

public static class DDActionBuilderExtentions
{
    public static DDAction StartAction<T>(this T self, Func<DDActionBuilder, DDAction> ab) where T : DDNode
    {
        var action = ab(new DDActionBuilder(self));
        DDActionManager.Instance.AddAction(action, self);
        return action;
    }

    public static DDIntervalAction Ease(this DDIntervalAction action, Func<float,float> func)
	{
        return new DDEase(action, func);
	}

    public static DDIntervalAction EaseElasticIn(this DDIntervalAction action, float period = 0.4f)
    {
        return new DDEaseElasticIn(action, period);
    }

    public static DDIntervalAction EaseElasticOut(this DDIntervalAction action, float period = 0.4f)
    {
        return new DDEaseElasticOut(action, period);
    }

    public static DDIntervalAction EaseNurbs(this DDIntervalAction action, params float [] args)
    {
        return new DDEase(action, it => DDMath.Nurbs(it, args));
    }

	public static DDIntervalAction EaseBounceOut(this DDIntervalAction action, float period = 0.4f)
	{
		return new DDEaseBounceOut(action);
	}

    public static DDIntervalAction EaseTimeScale(this DDIntervalAction action, float multiplier)
    {
        return new DDEaseTimeScale(action, multiplier);
    }


}
